package com.biz.primus.ms.payment.service;

import com.biz.primus.base.exception.BizSilentException;
import com.biz.primus.model.payment.vo.req.IWechatPaymentReqVo;
import com.biz.primus.model.payment.vo.req.PaymentRefundReqVo;
import com.biz.primus.model.payment.vo.req.PaymentReqVo;
import com.biz.primus.model.payment.vo.resp.CommonPaidRespVo;
import com.biz.primus.model.payment.vo.resp.PaymentRefundRespVo;
import com.biz.primus.model.payment.vo.resp.WechatPayResp;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.payment.channel.wechat.WeChatPayFactory;
import com.biz.primus.ms.payment.channel.wechat.exceptions.PaymentException;
import com.biz.primus.ms.payment.channel.wechat.lang.RefundStatus;
import com.biz.primus.ms.payment.channel.wechat.req.OrderRefund;
import com.biz.primus.ms.payment.channel.wechat.req.RefundQuery;
import com.biz.primus.ms.payment.channel.wechat.req.UnifiedOrder;
import com.biz.primus.ms.payment.channel.wechat.res.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import static com.biz.primus.ms.payment.channel.wechat.lang.Keys.*;

/**
 * Created by defei on 9/27/17.
 */
@Slf4j
@Service
public class WechatPaymentService extends AbstractBaseService {


    CommonPaidRespVo isPaid(Properties configProperties, String tradeNo, String mchOrderNo) {

        try {
            OrderQueryResponse orderQueryResponse = WeChatPayFactory.newInstance().newOrderQuery(configProperties, tradeNo, mchOrderNo).execute();
            return new CommonPaidRespVo(orderQueryResponse.getTradeNo(), orderQueryResponse.isPaid(), orderQueryResponse.getOpenId());
        } catch (Exception e) {
            throw new BizSilentException("Got an exception when query wechat payment status", e);
        }
    }

    /**
     * 统一下单
     */
    WechatPayResp createPayment(Properties configProperties, IWechatPaymentReqVo wechatPaymentReqVo, PaymentReqVo paymentReqVo) throws PaymentException {

        if (log.isDebugEnabled()) {
            log.debug("getMchOrderNo {}", paymentReqVo);
        }
        String errorMsg;
        try {
            WeChatPayFactory weChatPayFactory = WeChatPayFactory.newInstance();
            String timeExpire = DateUtils.formatDate(paymentReqVo.getExpireTime(), TIME_EXPIRE_DATE_FORMATER);
            UnifiedOrder unifiedOrder = weChatPayFactory.newUnifiedOrder(configProperties, paymentReqVo.getMchOrderNo(), paymentReqVo.getMchOrderNo(), paymentReqVo.getSubject(),
                    paymentReqVo.getPayAmount(), paymentReqVo.getClientIp(), wechatPaymentReqVo.getWechatTradeType(), timeExpire, wechatPaymentReqVo.getOpenid());
            unifiedOrder.setProperty(ATTACH, paymentReqVo.getMchId().toString());
            WechatPayRespVo unifiedOrderResponse = unifiedOrder.execute();
            if (log.isDebugEnabled()) {
                log.debug("Get response from wechat: {}", unifiedOrderResponse.getProperties());
            }
            if (unifiedOrderResponse.isProcessSuccess()) {
                WechatPayResp resp = new WechatPayResp();

                resp.setAppid(unifiedOrderResponse.getAppId());
                resp.setPartnerid(unifiedOrderResponse.getMchId());
                resp.setPrepayid(unifiedOrderResponse.getPrepayId());
                resp.setNoncestr(unifiedOrderResponse.getNonceStr());
                resp.setTimestamp(String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())));
                resp.setOrderId(paymentReqVo.getMchOrderNo());
                String sign = weChatPayFactory.newSigner(configProperties, configProperties.getProperty(KEY)).sign(resp);
                resp.setSign(sign);
                return resp;
            }
            errorMsg = StringUtils.isNotBlank(unifiedOrderResponse.getErrorDescption()) ? unifiedOrderResponse.getErrorDescption()
                    : unifiedOrderResponse.getReturnMessage();
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.error("生成预付单失败.", e);
            }
            errorMsg = e.getMessage();
        }
        throw new PaymentException(errorMsg);
    }

    /**
     * 退款
     */
    PaymentRefundRespVo refund(Properties configProperties, PaymentRefundReqVo paymentRefundReqVo) throws PaymentException {

        String errorMsg;
        try {
            OrderRefund orderRefund = WeChatPayFactory.newInstance().newOrderRefund(configProperties, null, paymentRefundReqVo.getMchOrderNo(), paymentRefundReqVo.getRefundNo(), paymentRefundReqVo.getTotalAmount(), paymentRefundReqVo.getRefundAmount());
            RefundResponse refundResponse = orderRefund.execute();
            if (refundResponse.isProcessSuccess()) {
                PaymentRefundRespVo paymentRefundRespVo = new PaymentRefundRespVo();
                paymentRefundRespVo.setProcessSuccess(true);
                paymentRefundRespVo.setRefundApplySuccess(true);
                paymentRefundRespVo.setOutRefundNo(paymentRefundReqVo.getRefundNo());
                return paymentRefundRespVo;
            } else {
                errorMsg = StringUtils.isNotBlank(refundResponse.getErrorDescption()) ? refundResponse.getErrorDescption()
                        : refundResponse.getReturnMessage();
            }
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.error("微信退款失败，退款单:{}.", paymentRefundReqVo, e);
            }
            errorMsg = e.getMessage();
        }
        throw new PaymentException(errorMsg);
    }

    /**
     * 退款状态查询
     */
    PaymentRefundRespVo refundQuery(Properties configProperties, PaymentRefundReqVo paymentRefundReqVo) throws PaymentException {

        String errorMsg;
        try {
            RefundQuery refundQuery = WeChatPayFactory.newInstance().newRefundQuery(configProperties, null, paymentRefundReqVo.getRefundNo());
            RefundQueryResponse queryResponse = refundQuery.execute();
            if (queryResponse.isProcessSuccess()) {
                PaymentRefundRespVo paymentRefundRespVo = parseRefundQueryResponse(queryResponse);
                paymentRefundRespVo.setOutRefundNo(paymentRefundReqVo.getRefundNo());
                return paymentRefundRespVo;
            } else {
                errorMsg = StringUtils.isNotBlank(queryResponse.getErrorDescption()) ? queryResponse.getErrorDescption()
                        : queryResponse.getReturnMessage();
            }
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.error("查询退款失败.", e);
            }
            errorMsg = e.getMessage();
        }
        throw new PaymentException(errorMsg);
    }

    /**
     * 只做解析，不做校验
     *
     * @param xmlBody 微信发送过来的通知
     */
    WechatPayNotifyRespVo parsePayNotifyRespVo(String xmlBody) {
        WechatPayNotifyRespVo notifyRes = new WechatPayNotifyRespVo(xmlBody, "xml");
        return notifyRes;
    }

    private PaymentRefundRespVo parseRefundQueryResponse(RefundQueryResponse queryResponse) {
        RefundStatus refundStatus = queryResponse.getRefundStatus();
        PaymentRefundRespVo paymentRefundRespVo = new PaymentRefundRespVo();
        paymentRefundRespVo.setRefundApplySuccess(true);
        paymentRefundRespVo.setRefunding(Objects.equals(refundStatus, RefundStatus.PROCESSING));
        paymentRefundRespVo.setRefundSuccess(Objects.equals(refundStatus, RefundStatus.SUCCESS));
        paymentRefundRespVo.setRetryAble(Objects.equals(refundStatus, RefundStatus.NOTSURE));
        paymentRefundRespVo.setNeedManualCheck(Objects.equals(refundStatus, RefundStatus.CHANGE));
        return paymentRefundRespVo;
    }
}
